/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { csMarked } from './csMarked.js';
import { csMark } from './csMark.js';
import { csUnflip } from './csUnflip.js';
/**
 * Depth-first search computes the nonzero pattern xi of the directed graph G (Matrix) starting
 * at nodes in B (see csReach()).
 *
 * @param {Number}  j               The starting node for the DFS algorithm
 * @param {Matrix}  g               The G matrix to search, ptr array modified, then restored
 * @param {Number}  top             Start index in stack xi[top..n-1]
 * @param {Number}  k               The kth column in B
 * @param {Array}   xi              The nonzero pattern xi[top] .. xi[n - 1], an array of size = 2 * n
 *                                  The first n entries is the nonzero pattern, the last n entries is the stack
 * @param {Array}   pinv            The inverse row permutation vector, must be null for L * x = b
 *
 * @return {Number}                 New value of top
 *
 * Reference: http://faculty.cse.tamu.edu/davis/publications.html
 */

export function csDfs(j, g, top, xi, pinv) {
  // g arrays
  var index = g._index;
  var ptr = g._ptr;
  var size = g._size; // columns

  var n = size[1]; // vars

  var i, p, p2; // initialize head

  var head = 0; // initialize the recursion stack

  xi[0] = j; // loop

  while (head >= 0) {
    // get j from the top of the recursion stack
    j = xi[head]; // apply permutation vector

    var jnew = pinv ? pinv[j] : j; // check node j is marked

    if (!csMarked(ptr, j)) {
      // mark node j as visited
      csMark(ptr, j); // update stack (last n entries in xi)

      xi[n + head] = jnew < 0 ? 0 : csUnflip(ptr[jnew]);
    } // node j done if no unvisited neighbors


    var done = 1; // examine all neighbors of j, stack (last n entries in xi)

    for (p = xi[n + head], p2 = jnew < 0 ? 0 : csUnflip(ptr[jnew + 1]); p < p2; p++) {
      // consider neighbor node i
      i = index[p]; // check we have visited node i, skip it

      if (csMarked(ptr, i)) {
        continue;
      } // pause depth-first search of node j, update stack (last n entries in xi)


      xi[n + head] = p; // start dfs at node i

      xi[++head] = i; // node j is not done

      done = 0; // break, to start dfs(i)

      break;
    } // check depth-first search at node j is done


    if (done) {
      // remove j from the recursion stack
      head--; // and place in the output stack

      xi[--top] = j;
    }
  }

  return top;
}